package com.mxchip.livestarmobile.mobile.ui.call

import android.annotation.SuppressLint
import android.media.AudioManager
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import com.trello.lifecycle2.android.lifecycle.AndroidLifecycle
import com.trello.rxlifecycle3.LifecycleProvider
import com.mxchip.livestarmobile.mobile.constant.RxConstant
import com.mxchip.livestarmobile.mobile.repository.RoomClientRepository
import com.mxchip.livestarmobile.mobile.state.SystemData
import com.mxchip.livestarmobile.mobile.util.Log.FileLog
import com.mxchip.livestarmobile.mobile.util.Log.MyLog
import com.mxchip.livestarmobile.mobile.util.RxBus.RxBus
import com.mxchip.livestarmobile.mobile.util.RxBus.RxSchedulersHelper
import com.videohigh.hxb.roomclient.event.*
import com.mxchip.livestarmobile.mobile.base.toast
import io.reactivex.Observable
import kotlinx.android.synthetic.main.fragment_call_control.*
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.*
import com.mxchip.livestarmobile.R
import com.mxchip.livestarmobile.mobile.state.AppConstant
import com.orhanobut.hawk.Hawk
import kotlinx.coroutines.Job


class CallControlFragment : Fragment() {

    private val provider: LifecycleProvider<Lifecycle.Event> = AndroidLifecycle.createLifecycleProvider(this)

    private val dbyViewModel by activityViewModels<DbyViewModel>()

    private val callControlViewModel by activityViewModels<CallControlViewModel>()
    private val roomViewModel by activityViewModels<RoomViewModel>()
    private val screenViewModel by activityViewModels<ScreenViewModel>()

    private lateinit var hangupEventObservable: Observable<HangupEvent>
    private lateinit var invitationEventObservable: Observable<InvitationEvent>
    private lateinit var enterEventObservable: Observable<EnterEvent>
    private lateinit var disconnectEventObservable: Observable<Boolean>
    private lateinit var reconnectEventObservable: Observable<Boolean>

    private lateinit var shareContentAddEventObservable: Observable<ShareContentAddEvent>
    private lateinit var shareContentRemoveEventObservable: Observable<ShareContentRemoveEvent>

    private val logger: FileLog = FileLog.getLogger(CallControlFragment::class.java)

    private var keepAliveJob: Job? = null

    private val mAudioManage by lazy {
        context?.let { ContextCompat.getSystemService(it, AudioManager::class.java) }
    }

    override fun onDestroyView() {
        super.onDestroyView()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        initRxBus()
        openDevices()
    }

    fun openDevices() {
        val muteAudio: Boolean = Hawk.get(AppConstant.SP_MUTE_AUDIO) ?: false
        val closeCamera: Boolean = Hawk.get(AppConstant.SP_CLOSE_CAMERA) ?: false
        if (!muteAudio)
            dbyViewModel.mic(true)
        if (!closeCamera)
            dbyViewModel.camera(true)
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        // Inflate the layout for this fragment
        val view = inflater.inflate(R.layout.fragment_call_control, container, false)

        ViewCompat.setTranslationZ(view, -1f)

        return view
    }

    @SuppressLint("CheckResult")
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        dbyViewModel.camera.observe(viewLifecycleOwner, Observer { isOpen ->

            val roomId = roomViewModel.roomId.value!!
            val channelId = roomViewModel.channelId.value!!
            val callIndex = roomViewModel.callIndex.value!!

            if (isOpen) {

                RoomClientRepository.addVideoDevice(roomId, channelId, callIndex, arrayOf(AVDevice.CAMERA_LOCAL, AVDevice.CAMERA_LOCAL_SMALL))

                button_camera.isSelected = false
                button_camera.setImageResource(R.drawable.icon_incall_camera_button)
                text_camera.text = getString(R.string.close_camera)
            } else {

                RoomClientRepository.removeVideoDevice(roomId, channelId, callIndex, arrayOf(AVDevice.CAMERA_LOCAL, AVDevice.CAMERA_LOCAL_SMALL))

                button_camera.isSelected = true
                button_camera.setImageResource(R.drawable.icon_incall_camera_off_button)
                text_camera.text = getString(R.string.open_camera)
            }
        })

        dbyViewModel.mic.observe(viewLifecycleOwner, Observer { open ->

            if (!open) {
                button_mic.isSelected = true
                button_mic.setImageResource(R.drawable.icon_incall_mic_off_button)
                text_mic.text = getString(R.string.open_mic)
            } else {
                button_mic.isSelected = false
                button_mic.setImageResource(R.drawable.icon_incall_mic_button)
                text_mic.text = getString(R.string.clse_mic)
            }
        })

        roomViewModel.isMyselfTheOnlyOneLeft.observe(viewLifecycleOwner, Observer {
            if (it == true) {
                logger.info(SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date()) + " CallControlFragment hangup sessionsCall size <= 1---->");

                reqHangup()
            }
        })

        callControlViewModel.isShow().observe(viewLifecycleOwner, Observer { isShow ->
            group_toolbar.apply {
                visibility = if (!isShow) View.INVISIBLE else View.VISIBLE
            }.requestLayout()
        })

        dbyViewModel.callControlTouched.observe(viewLifecycleOwner, Observer { touched ->
            callControlViewModel.touched()
        })



        keepAliveJob = lifecycleScope.launch {
            while (true) {
                val roomId = roomViewModel.roomId.value
                val channelId = roomViewModel.channelId.value
                val callIndex = roomViewModel.callIndex.value

                if (!roomId.isNullOrBlank() && !channelId.isNullOrBlank() && !callIndex.isNullOrBlank()) {
                    RoomClientRepository.keepAliveChannel(roomId, channelId, callIndex) {
                        if (it.result != 0 && keepAliveJob?.isCancelled != false) {
                            lifecycleScope.launch {
                                toast("当前网络差，正在退出通话...")
                                delay(1500)
                                reqHangup()
                            }
                        }
                    }
                }


                delay(1000)
            }
        }

        lifecycleScope.launch {
            while (true) {

                keepAndSyncAlive()

                delay(30*1000)
            }
        }
        button_mic.setOnClickListener {
            dbyViewModel.mic(!dbyViewModel.mic.value!!)
        }

        button_camera.setOnClickListener {
            dbyViewModel.camera(!dbyViewModel.camera.value!!)
        }


        button_hangup.setOnClickListener {
            logger.info(SimpleDateFormat("yyyy-MM-dd-HH:mm:ss", Locale.CHINA).format(Date()) + "onHangupClick Event.hungupBtnClick reqHangup")
            reqHangup()

        }

        button_hide_small_view.setOnClickListener {

            val mainScreenMode = screenViewModel.mainScreenMode()

            if (!mainScreenMode) {
                text_hide_small_view.text = getString(R.string.show_small_view)
            } else {
                text_hide_small_view.text = getString(R.string.hide_small_view)
            }

            screenViewModel.mainScreenMode(!mainScreenMode)
        }

        button_invite.setOnClickListener {
            findNavController().navigate(R.id.action_callControlFragment_to_inviteDialogFragment)
        }

        root_container.setOnClickListener {
            callControlViewModel.touched()
        }

        button_volume.setOnClickListener {
            mAudioManage?.adjustStreamVolume(AudioManager.STREAM_VOICE_CALL, AudioManager.ADJUST_SAME, AudioManager.FLAG_SHOW_UI)
        }
    }

    @SuppressLint("CheckResult")
    private fun initRxBus() {
        //通话中添加成员-通知已经在房间中的人
        invitationEventObservable = RxBus.get().register(RxConstant.INVITATION_EVENT, InvitationEvent::class.java)
        invitationEventObservable./*compose(provider.bindToLifecycle()).*/compose(RxSchedulersHelper.io_main())
                .subscribe(::onInvitation) { error -> error.printStackTrace() }

        //被动挂断
        hangupEventObservable = RxBus.get().register(RxConstant.HANGUP_EVENT, HangupEvent::class.java)
        hangupEventObservable./*compose(provider.bindToLifecycle()).*/compose(RxSchedulersHelper.io_main())
                .subscribe(::onHangup) { error -> error.printStackTrace() }

        //主叫收到被叫的 接听/挂断 消息
        enterEventObservable = RxBus.get().register(RxConstant.ENTER_EVENT, EnterEvent::class.java)
        enterEventObservable./*compose(provider.bindToLifecycle()).*/compose(RxSchedulersHelper.io_main())
                .subscribe(::onEnter) { error -> error.printStackTrace() }


        //接收对端发来的 ppt共享/ppt关闭
        shareContentAddEventObservable = RxBus.get().register(RxConstant.SHARE_CONTENT_ADD_EVENT, ShareContentAddEvent::class.java)
        shareContentAddEventObservable./*compose(provider.bindToLifecycle()).*/compose(RxSchedulersHelper.io_main())
                .subscribe(::onShareContentAddEvent) { error ->
                    run {
                        logger.error(SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date()) +
                                " shareContentAddEventObservable" + error.message)
                        error.printStackTrace()
                    }
                }

        shareContentRemoveEventObservable = RxBus.get().register(RxConstant.SHARE_CONTENT_REMOVE_EVENT, ShareContentRemoveEvent::class.java)
        shareContentRemoveEventObservable./*compose(provider.bindToLifecycle()).*/compose(RxSchedulersHelper.io_main())
                .subscribe(::onShareContentRemoveEvent) { error ->
                    run {
                        logger.error(SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date()) +
                                " shareContentRemoveEventObservable" + error.message)
                        error.printStackTrace()
                    }
                }


        disconnectEventObservable = RxBus.get().register(RxConstant.DISCONNECT, Boolean::class.java)
        disconnectEventObservable./*compose(provider.bindToLifecycle()).*/compose(RxSchedulersHelper.io_main())
                .subscribe(::onDisconnect) { error -> error.printStackTrace() }

        reconnectEventObservable = RxBus.get().register(RxConstant.RECONNECT, Boolean::class.java)
        reconnectEventObservable./*compose(provider.bindToLifecycle()).*/compose(RxSchedulersHelper.io_main())
                .subscribe(::onReConnect) { error -> error.printStackTrace() }

    }


    override fun onDestroy() {
        super.onDestroy()
        RxBus.get().unregister(RxConstant.HANGUP_EVENT, hangupEventObservable)
        RxBus.get().unregister(RxConstant.INVITATION_EVENT, invitationEventObservable)
        RxBus.get().unregister(RxConstant.SHARE_CONTENT_ADD_EVENT, shareContentAddEventObservable)
        RxBus.get().unregister(RxConstant.ENTER_EVENT, enterEventObservable)
        RxBus.get().unregister(RxConstant.SHARE_CONTENT_REMOVE_EVENT, shareContentRemoveEventObservable)
        RxBus.get().unregister(RxConstant.DISCONNECT, disconnectEventObservable)
        RxBus.get().unregister(RxConstant.RECONNECT, reconnectEventObservable)

    }

    private fun onInvitation(event: InvitationEvent) {
        // busyAddMemberView(s,null);
        // val callingInvitationEventInvite: InviteNotifyNewEvent = Gson().fromJson(s, InviteNotifyNewEvent::class.java)

        logger.info(SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date()) +
                " busyAddMemberView InvitationEvent:" + event)

        event.invitationNumbers.forEach {
            val termNumber = "${it.roomId}T${it.termId}"

            val sessionsAll = roomViewModel.sessionsAll.value

            if (!sessionsAll.isNullOrEmpty() && !sessionsAll.contains(termNumber)) {
                roomViewModel.onJoinRoom(termNumber)
            }
        }
    }

    private fun onHangup(event: HangupEvent) {
        Log.e("CallControlFragment", "onHangup: $event")
        MyLog.logD(MyLog.SIGNALLING_MODEL, "signaling server respRelease removeTermId(bean):${event} ---->")
        logger.info(SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA).format(Date()) +
                "CallControlFragment::respRelease: roomViewModel.videoDevices:${event}")

        // roomViewModel.videoDevices(bean.room.videoDevices!!)
        Log.e("CallControlFragment", "onHangup: ${roomViewModel.sessionsAll.value}")

        val termNumber = "${event.from.roomId}T${event.from.termId}"
        roomViewModel.onLeaveRoom(termNumber)

        Log.e("CallControlFragment", "onHangup: ${roomViewModel.sessionsAll.value}")
    }


    private fun onEnter(event: EnterEvent) {
        Log.e("CallControlFragment", "respInviteAccept: $event")

        val termNumber = "${event.from.roomId}T${event.from.termId}"

        roomViewModel.onStartCallRoom(termNumber)
    }

    private fun onShareContentAddEvent(event: ShareContentAddEvent) {
        val fromTermNumber = "${event.from.roomId}T${event.from.termId}"
        roomViewModel.addAVDevice(AVDevice(fromTermNumber, event.deviceName))

        // SystemData.getInstance().receiveWifiResState = true

        if (SystemData.getInstance().mediaCodecReadyState) {
//            SystemData.getInstance().streamMode = StreamMode.RECEIVE_DOUBLE
            dbyViewModel.showRemoteResView(true)
        }
    }

    private fun onShareContentRemoveEvent(event: ShareContentRemoveEvent) {
        val fromTermNumber = "${event.from.roomId}T${event.from.termId}"
        roomViewModel.removeAVDevice(fromTermNumber, event.deviceName)
        // SystemData.getInstance().receiveWifiResState = false

        if (SystemData.getInstance().mediaCodecReadyState) {
//            SystemData.getInstance().streamMode = StreamMode.SINGLE
            dbyViewModel.showRemoteResView(false)
        }
    }

    private fun onReConnect(v: Boolean) {
        disconnectHangupJob?.cancel()
        keepAndSyncAlive()

    }

    private fun keepAndSyncAlive() {
        lifecycleScope.launch {
            val roomId = roomViewModel.roomId.value!!
            val channelId = roomViewModel.channelId.value!!
            val callIndex = roomViewModel.callIndex.value!!
            while (!RoomClientRepository.connected()) {
                delay(1)
            }
            RoomClientRepository.syncAndKeepAliveChannel(roomId, channelId, callIndex) {

                if (it.result != 0) {
                    lifecycleScope.launch {
                        toast("当前网络差，正在退出通话...")
                        delay(1500)
                        logger.info(SimpleDateFormat("yyyy-MM-dd-HH:mm:ss", Locale.CHINA).format(Date()) + " onReConnect keepAliveChannel reqHangup")
                        reqHangup()

                    }
                } else {
                    lifecycleScope.launch {
                        val list = ArrayList<String>()
                        it.terms.forEach { term ->
                            list.add("${term.roomId}T${term.termId}")
                        }
                        roomViewModel.resetSessionsCall(list)

                        val devices = ArrayList<AVDevice>()
                        it.terms.forEach { term ->
                            if (term.termId != SystemData.userId()) {
                                term.deviceNames?.forEach { device ->
                                    val avDevice = AVDevice("${term.roomId}T${term.termId}", device)
                                    devices.add(avDevice)
                                }
                            }
                        }
                        roomViewModel.replaceAVDevice(devices)
                    }

                }
            }
        }
    }

    private var disconnectHangupJob: Job? = null
    private fun onDisconnect(v: Boolean) {
        toast("当前网络差，正在尝试重连...")
        disconnectHangupJob = lifecycleScope.launch {
            delay(30 * 1000)
            reqHangup()
        }
    }


    override fun onPause() {
        super.onPause()
        if (!isHangup) {
            logger.info(SimpleDateFormat("yyyy-MM-dd-HH:mm:ss", Locale.CHINA).format(Date()) + "onPause Event.hungupBtnClick reqHangup")
            reqHangup()
        }
    }


    var isHangup = false
    private fun reqHangup() {
        isHangup = true
        logger.info(SimpleDateFormat("yyyy-MM-dd-HH:mm:ss", Locale.CHINA).format(Date()) + " Event.hungupBtnClick reqHangup")
        keepAliveJob?.cancel()
        val roomId = roomViewModel.roomId.value
        val channelId = roomViewModel.channelId.value
        val callIndex = roomViewModel.callIndex.value

        if (!roomId.isNullOrBlank() && !channelId.isNullOrBlank() && !callIndex.isNullOrBlank()) {
            RoomClientRepository.hangup(roomId, channelId, callIndex)
        }
        dbyViewModel.join(null)
    }

}